<!DOCTYPE html>
<html lang="zh">
<head>
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>

    <title>BotMan一下 => Push Anything To Anywhere</title>

    <!-- 引入 layui css -->
    <link href="https://cdn.staticfile.org/layui/2.7.6/css/layui.css" rel="stylesheet">
    <!-- 备用 -->
    <!-- <link href="//unpkg.com/layui@2.7.6/dist/css/layui.css" rel="stylesheet"> -->
    <base>
    <!-- 这是jquery库 -->
    <script src="https://cdn.bootcss.com/jquery/3.3.1/jquery.min.js"></script>
    <!-- 使用 2.5.0 版本 适配 netty-socketio 这个库 -->
    <script src="https://cdn.bootcss.com/socket.io/2.5.0/socket.io.js"></script>
    <!--下面的最新版本 有些不兼容的地方 -->
    <!-- <script src="https://cdn.bootcss.com/socket.io/4.5.0/socket.io.js"></script> -->
    <!-- day.js -->
    <script src="https://unpkg.com/dayjs@1.11.4/dayjs.min.js"></script>
    <!-- party.js -->
    <!-- <script src="https://cdn.jsdelivr.net/npm/party-js@latest/bundle/party.min.js"></script> -->
    <!-- confetti js -->
    <script src="https://cdn.jsdelivr.net/npm/canvas-confetti@1.5.1/dist/confetti.browser.min.js"></script>
    <!-- layui notify js -->
    <!-- 位于 src/main/resources/static/notify_stand.js -->
    <script src="notify_stand.js"></script>
    <!-- 下面写法也可 -->
    <!-- <script src="/notify_stand.js"></script> -->

    <style>
        body {
            padding: 20px;
        }

        #console {
            height: 450px;
            overflow: auto;
        }

        .username-msg {
            color: orange;
        }

        .connect-msg {
            color: green;
        }

        .disconnect-msg {
            color: red;
        }
    </style>
</head>

<body>
<h1>BotMan一下</h1>

<div style="padding: 25px 0 17px;">
    <blockquote class="layui-elem-quote">
        BotMan => Push Anything To Anywhere
    </blockquote>
</div>

<!-- 这个不是 方框风格的表单 -->
<!-- 将此 form标签的class加上【layui-form-pane】就是 pane-方框风格的表单 -->
<!-- <form class="layui-form layui-form-pane" action=""> -->
<form class="layui-form" action="">

    <div style="border: 1px;">

        <!--    <label>socketurl:</label><input type="text" id="url2" value="http://localhost:9090"> -->

        <div class="layui-form-item">
            <label class="layui-form-label">socketurl</label>
            <div class="layui-input-inline">
                <input type="text" id="url" name="url" autocomplete="off" placeholder="请输入socketurl" class="layui-input"
                       value="http://localhost:9090">
            </div>
        </div>

        <br>

        <!-- <label>clientId:</label><input type="text" id="clientId" value="123456">-->

        <div class="layui-form-item">
            <label class="layui-form-label">clientId</label>
            <div class="layui-input-inline">
                <input type="text" id="clientId" name="clientId" autocomplete="off" placeholder="请输入clientId"
                       class="layui-input"
                       value="123456">
            </div>
        </div>

        <br>

        <!-- <label>userId:</label><input type="text" id="userId" value="ahviplc">-->

        <div class="layui-form-item">
            <label class="layui-form-label">userId</label>
            <div class="layui-input-inline">
                <input type="text" id="userId" name="userId" autocomplete="off" placeholder="请输入userId"
                       class="layui-input"
                       value="ahviplc">
            </div>
        </div>

        <br>

        <div class="layui-form-item" style="margin-left: 91px">
            <!--<button id="connect">connect</button>-->
            <button type="button" class="layui-btn layui-btn-sm" id="connect">connect</button>
            <!--<button id="disconnect">disconnect</button>-->
            <button type="button" class="layui-btn layui-btn-sm" id="disconnect">disconnect</button>
        </div>
    </div>

    <br>

    <div style="border: 1px;">

        <!--    <label>socketEvent:</label>-->
        <!--    <input type="text" id="socketEvent" placeholder="botManFromHTML" value="botManFromHTML">-->

        <div class="layui-form-item">
            <label class="layui-form-label">socketEvent</label>
            <div class="layui-input-inline">
                <input type="text" id="socketEvent" name="socketEvent" autocomplete="off" placeholder="请输入socketEvent"
                       class="layui-input"
                       value="botManFromHTML">
            </div>
        </div>

        <br>

        <!--    <label>content:</label>-->

        <div class="layui-form-item">
            <label class="layui-form-label">聊天内容</label>
            <div class="layui-input-inline">
                <textarea id="content" maxlength="1000" cols="30" rows="5"
                          class="layui-textarea">hello world...</textarea>
            </div>
        </div>

        <br>

        <div class="layui-form-item" style="margin-left: 91px">
            <!-- <button id="send">send</button> -->
            <button type="button" class="layui-btn layui-btn-sm" id="send" title="发送字符串消息按钮">send</button>
            <!-- <button id="sendWithObj">sendWithObj</button> -->
            <button type="button" class="layui-btn layui-btn-sm" id="sendWithObj" title="发送结构体消息按钮">sendWithObj</button>
            <button type="button" class="layui-btn layui-btn-sm" id="sendWithGroup" title="群发|群聊按钮">sendWithGroup(群发)</button>
        </div>
    </div>
</form>

<br>

<fieldset class="layui-elem-field layui-field-title" style="margin-top: 32px;">
    <legend>消息展示区</legend>
</fieldset>
<pre class="layui-code" lay-options="{title: '消息展示区', skin: 'dark',ln: true}">
<div id="console" class="well"></div>
</pre>

</body>
<!-- 引入 layui js -->
<script src="https://cdn.staticfile.org/layui/2.7.6/layui.js"></script>
<!-- 备用 -->
<!-- <script src="//unpkg.com/layui@2.7.6/dist/layui.js"></script> -->
<!-- socket io 逻辑 -->
<script type="text/javascript">
    var socket;
    var errorCount = 0;
    var isConnected = false;
    var maxError = 5;

    // connect(null,null);

    function connect(url, clientId, userId) {
        if (url == '' || url == null || url == undefined) {
            url = 'http://localhost:9090';
        }

        if (clientId == '' || clientId == null || clientId == undefined) {
            clientId = 7729;
        }

        if (userId == '' || userId == null || userId == undefined) {
            userId = 'ahviplc';
        }

        // 拼接请求参数对象
        var opts = {
            query: 'clientId=' + clientId + '&' + 'userId=' + userId,
            transports: ['websocket'], // 传输模式定为 websocket 会比 polling 稳点 更不易掉线 更稳定【和服务端代码对应上 com/lc/mySocketIO/SocketConfig.java:88】
        };

        // 目前使用传入参数对象的方式 初始化 socket
        socket = io.connect(url, opts);

        socket.on('connect', function () {
            isConnected = true;
            console.log("连接成功");
            serverOutput('<span class="connect-msg"><font color="blue">' + getNowTime() + '&nbsp;</font>' + '连接成功' + '</span>');
            console.log("connect socket.connected => ", socket.connected); // true
            errorCount = 0;
        });

        // 接收从服务端传来的消息 sendEvent = message
        socket.on('message', function (data) {
            output('<span class="username-msg"><font color="blue">' + getNowTime() + '&nbsp;</font>' + data + ' </span>');
            console.log("sendEvent = message => ", data);
        });

        // 接收从服务端传来的消息 sendEvent = botManFromServer
        socket.on('botManFromServer', function (data) {
            output('<span class="username-msg"><font color="blue">' + getNowTime() + '&nbsp;</font>' + data + ' </span>');
            console.log("sendEvent = botManFromServer => ", data);
        });

        // 接收从服务端传来的消息 sendEvent = botManFromServerWithObj 结构体消息数据
        socket.on('botManFromServerWithObj', function (data) {
            output('<span class="username-msg"><font color="blue">' + getNowTime() + '&nbsp;</font>' + data.msgContent + ' </span>');
            console.log("sendEvent = botManFromServerWithObj => ", data);
        });

        // 群发事件 | 群聊
        // 接收从服务端传来的消息 sendEvent = botManFromServerWithGroup 结构体消息数据
        socket.on('botManFromServerWithGroup', function (data) {
            output('<span class="username-msg"><font color="#556b2f">' + getNowTime() + '&nbsp;</font>' + data.msgContent + ' </span>');
            console.log("sendEvent = botManFromServerWithGroup => ", data);
        });

        // 接收从服务端传来的消息 sendEvent = onEventMsgSendStatusToHTML 结构体消息数据
        socket.on('onEventMsgSendStatusToHTML', function (data) {
            // 如果消息类型为空 则设置为 RealTimeMessage 当实时消息处理
            if (data.msgType == null) {
                data.msgType = 'RealTimeMessage'
            }

            // 共同逻辑
            output('<span class="username-msg"><font color="blue">' + getNowTime() + '&nbsp;</font>' + data.msgContent + ' </span>');
            console.log("sendEvent = onEventMsgSendStatusToHTML => ", data);

            // 如果这是缓存消息
            // 则会对应下发一个消息抵达响应 去为了真正的删除 缓存在内存中的消息 这样也可以保证 缓存消息不丢失
            if (data.msgType == 'CachedMessage') { // 缓存消息
                // 监听缓存消息的发送状态的消息事件 onEventMsgSendStatus
                // data.beOperatedId 存放的是 缓存中的 key
                // 直接原数据返回即可 后台可通过 data.beOperatedId 在缓存中 将其删除
                socket.emit('onEventMsgSendStatus', data);
                // 同时通知弹框 消息提示 layui风格
                // src/main/resources/static/notify_stand.js
                // 显示内容为缓存发送的消息内容 右上角显示 10秒后自动关闭 显示关闭按钮
                // 根据后面参数的数据类型直接对应是针对哪一个配置项 | msg | position | duration | showClose | 回调函数
                // 具体代码实现可见 static/notify_stand.js:145
                notify.info(data.msgContent, "topRight", 10000);
            }
        });

        socket.on('disconnect', function () {
            isConnected = false;
            console.log("连接断开");
            serverOutput('<span class="disconnect-msg"><font color="blue">' + getNowTime() + '&nbsp;</font>' + '已下线! </span>');
            console.log("disconnect socket.connected => ", socket.connected); // true
        });

        socket.on('connect_error', function (data) {
            serverOutput('<span class="disconnect-msg"><font color="blue">' + getNowTime() + '&nbsp;</font>' + '连接错误->' + data + ' </span>');
            errorCount++;
            if (errorCount >= maxError) {
                socket.disconnect();
            }
        });

        socket.on('connect_timeout', function (data) {
            serverOutput('<span class="disconnect-msg"><font color="blue">' + getNowTime() + '&nbsp;</font>' + '连接超时->' + data + ' </span>');
            errorCount++;
            if (errorCount >= maxError) {
                socket.disconnect();
            }
        });

        socket.on('error', function (data) {
            serverOutput('<span class="disconnect-msg"><font color="blue">' + getNowTime() + '&nbsp;</font>' + '系统错误->' + data + ' </span>');
            errorCount++;
            if (errorCount >= maxError) {
                socket.disconnect();
            }
        });

        socket.on('ack', function (data) {
            var str = '消息发送失败';
            if (data == 1) {
                str = '消息发送成功';
            }
            serverOutput('<span class="connect-msg"><font color="blue">' + getNowTime() + '&nbsp;</font>' + str + ' </span>');
        });
    }

    function output(message) {
        var element = $("<div>" + " " + message + "</div>");
        $('#console').prepend(element);
    }

    function serverOutput(message) {
        var element = $("<div>" + message + "</div>");
        $('#console').prepend(element);
    }

    $("#connect").click(function () {
        if (!isConnected) {
            var url = $("#url").val();
            var clientId = $("#clientId").val();
            var userId = $("#userId").val();
            connect(url, clientId, userId);
        }
    })

    // 点击这里的时候 此 socket 就已经 disconnect
    $("#disconnect").click(function () {
        if (isConnected) {
            socket.disconnect();
        }
    })

    $("#send").click(function () {
        var socketEvent = $("#socketEvent").val();
        var content = $("#content").val();

        //  socket.emit(socketEvent, content);

        try {
            // 升级写法 考虑到离线情况
            if (socket.connected) {
                socket.emit(socketEvent, content);
                serverOutput('<span class="connect-msg"><font color="blue">' + getNowTime() + '&nbsp;</font>' + 'send | 发送消息-> ' + content + ' </span>');
            } else {
                console.log("离线了 不可以发送了 socket.connected => ", socket.connected)
                serverOutput('<span class="connect-msg"><font color="red">' + getNowTime() + '&nbsp;</font>' + '离线了 不可以发送了' + ' </span>');
            }
        } catch (err) {
            if (err.message = "Cannot read properties of undefined (reading 'connected')") {
                // alert('请先connect 再点我')
                layer.msg('请先connect 再点我')
            } else {
                // alert(err.message);
                layer.msg(err.message);
            }
        }
    })

    // 发送带有结构体的消息数据
    // 后端接收socket事件 botManFromHTMLWithObj
    $("#sendWithObj").click(function () {
        var socketEvent = 'botManFromHTMLWithObj';
        var userId = $("#userId").val();
        var content = $("#content").val();

        // 拼接消息结构体
        let thisObj = {
            userId: userId,
            msgContent: content,
            msgType: 'RealTimeMessage'
        }

        try {
            // 升级写法 考虑到离线情况
            if (socket.connected) {
                socket.emit(socketEvent, thisObj);
                serverOutput('<span class="connect-msg"><font color="blue">' + getNowTime() + '&nbsp;</font>' + 'sendWithObj | 发送消息-> ' + content + ' </span>');
            } else {
                console.log("离线了 不可以发送了 socket.connected => ", socket.connected)
                serverOutput('<span class="connect-msg"><font color="red">' + getNowTime() + '&nbsp;</font>' + '离线了 不可以发送了' + ' </span>');
            }
        } catch (err) {
            if (err.message = "Cannot read properties of undefined (reading 'connected')") {
                // alert('请先connect 再点我')
                layer.msg('请先connect 再点我')
            } else {
                // alert(err.message);
                layer.msg(err.message);
            }
        }
    })

    // 群发按钮 | 群聊
    // 发送带有结构体的消息数据
    // 后端接收socket事件 botManFromHTMLWithGroup
    $("#sendWithGroup").click(function () {
        var socketEvent = 'botManFromHTMLWithGroup';
        var userId = $("#userId").val();
        var content = $("#content").val();

        // 拼接消息结构体
        let thisObj = {
            userId: userId,
            msgContent: content,
            msgType: 'RealTimeMessage'
        }

        try {
            // 升级写法 考虑到离线情况
            if (socket.connected) {
                socket.emit(socketEvent, thisObj);
                serverOutput('<span class="connect-msg"><font color="blue">' + getNowTime() + '&nbsp;</font>' + 'sendWithGroup | 发送消息-> ' + content + ' </span>');
            } else {
                console.log("离线了 不可以发送了 socket.connected => ", socket.connected)
                serverOutput('<span class="connect-msg"><font color="red">' + getNowTime() + '&nbsp;</font>' + '离线了 不可以发送了' + ' </span>');
            }
        } catch (err) {
            if (err.message = "Cannot read properties of undefined (reading 'connected')") {
                // alert('请先connect 再点我')
                layer.msg('请先connect 再点我')
            } else {
                // alert(err.message);
                layer.msg(err.message);
            }
        }

        // 撒花特效 | can work | 这个各别浏览器无法出效果
        // https://github.com/yiliansource/party-js
        // party.confetti(this, {
        //     count: party.variation.range(20, 40),
        // });

        // confetti 五彩纸屑 | can work
        // https://github.com/catdad/canvas-confetti
        // 挂载在  window 对象。它表示浏览器窗口,所有 JavaScript 全局对象、函数以及变量均自动成为 window 对象的成员。
        window.confetti({
            particleCount: 100,
            startVelocity: 30,
            spread: 360,
            origin: {
                x: Math.random(),
                // since they fall down, start a bit higher than random
                y: Math.random() - 0.2
            }
        });
    })

    // 使用 dayjs 库
    // 获取当前时间 格式化成 YYYY-MM-DD HH:mm:ss | 2022-08-05 09:35:18
    function getNowTime() {
        return dayjs().format('YYYY-MM-DD HH:mm:ss');
    }

    // 自己写的 不使用
    function getNowTime2() {
        var date = new Date();
        var year = date.getFullYear(); //获取当前年份
        var mon = date.getMonth() + 1; //获取当前月份
        var da = date.getDate(); //获取当前日
        var h = date.getHours(); //获取小时
        var m = date.getMinutes(); //获取分钟
        var s = date.getSeconds(); //获取秒
        var ms = date.getMilliseconds();
        var d = document.getElementById('Date');
        var date = year + '/' + mon + '/' + da + ' ' + h + ':' + m + ':' + s + ':' + ms;
        return date;
    }
</script>
</html>
